package com.mes.common.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Repository;

import com.bstek.dorado.data.provider.Page;
import com.mes.common.dao.iface.IBasicDao;
import com.mes.common.domain.BasicModel;
import com.mes.common.util.IdentityGenerator;

@SuppressWarnings(value = { "unchecked" })
@Repository
public class BasicDao<T> extends MMHibernateDao<T> implements IBasicDao<T> {

	@Override
	public void add(T t) throws Exception {
		// TODO Auto-generated method stub
		BasicModel basicModel = (BasicModel) t;
		if (basicModel.getUuid() == null) {
			basicModel.setUuid(IdentityGenerator.GetIdentityUUID());
		}

		super.add(t);
	}

	@Override
	public void update(T t) throws Exception {
		super.update(t);

	}

	@Override
	public void delete(T t) throws Exception {
		// TODO Auto-generated method stub
		super.delete(t);
	}
	
	@Override
	public void save(T t) throws Exception {
		// TODO Auto-generated method stub
		BasicModel basicModel = (BasicModel) t;
		if (basicModel.getObjectState() == BasicModel.OBJECTSTATE_TOBEADDED) {
			super.add(t);
		}else if (basicModel.getObjectState() == BasicModel.OBJECTSTATE_TOBEDELETED) {
			super.delete(t);
		}else if (basicModel.getObjectState() == BasicModel.OBJECTSTATE_TOBEUPDATED) {
			super.update(t);
		}
	}

	@Override
	public void add(Collection<T> collection) throws Exception {
		// TODO Auto-generated method stub
		for (T t : collection) {
			this.add(t);
		}
		;
	}

	@Override
	public void update(Collection<T> collection) throws Exception {
		// TODO Auto-generated method stub
		for (T t : collection) {
			this.update(t);
		}
		;
	}

	@Override
	public void delete(Collection<T> collection) throws Exception {
		// TODO Auto-generated method stub
		for (T t : collection) {
			this.delete(t);
		}
		;
	}

	@Override
	public List<T> loadAll(Class<T> clazz) throws Exception {
		// TODO Auto-generated method stub
		return super.loadAll(clazz);
	}

	@Override
	public T load(Class<T> clazz, Serializable id) throws Exception {
		// TODO Auto-generated method stub
		return super.load(clazz, id);
	}

	@Override
	public T get(Class<T> clazz, Serializable id) throws Exception {
		// TODO Auto-generated method stub
		return super.get(clazz, id);
	}

	private Class<?> getClazz() {
		Class<?> clazz = this.getClass();
		// 2得到子类对象的泛型父类类型
		ParameterizedType type = (ParameterizedType) clazz.getGenericSuperclass();
		Type[] types = type.getActualTypeArguments();
		clazz = (Class<T>) types[0];
		return clazz;
	}

	public List<T> loadAll() throws Exception {
		// TODO Auto-generated method stub
		return super.loadAll((Class<T>) this.getClazz());
	}

	public T load(Serializable id) throws Exception {
		// TODO Auto-generated method stub
		return super.load((Class<T>) this.getClazz(), id);
	}

	public T getById(Serializable id) throws Exception {
		// TODO Auto-generated method stub
		return super.get((Class<T>) this.getClazz(), id);
	}

	public void loadAll(Page<T> page) throws Exception {
		// TODO Auto-generated method stub
		super.pagingQuery(page, DetachedCriteria.forClass(this.getClazz()));
	}

	public List<T> findByProperty(String propertyName, Object value) throws Exception {
		Session session = this.getSessionFactory().getCurrentSession();
		Criteria criteria = session.createCriteria(getClazz());
		// DetachedCriteria criteria = DetachedCriteria.forClass(getClazz());
		if (value == null) {
			criteria.add(Restrictions.isNull(propertyName));
		} else {
			criteria.add(Restrictions.eq(propertyName, value.toString()));
		}

		return criteria.list();
	}

	public List<T> findByProperty(String propertyName, Object value, String orderBy) throws Exception {
		if (orderBy == null || "".equals(orderBy)) {
			return findByProperty(propertyName, value);
		}

		DetachedCriteria criteria = DetachedCriteria.forClass(getClazz());
		criteria.add(Restrictions.like(propertyName, value.toString(), MatchMode.START));
		criteria.addOrder(Property.forName(orderBy).asc());
		return (List<T>) this.query(criteria);
	}

	public List<T> findByProperty(String propertyName, Object value, String orderBy, boolean isDesc) throws Exception {
		if (orderBy == null || "".equals(orderBy)) {
			return findByProperty(propertyName, value);
		}

		DetachedCriteria criteria = DetachedCriteria.forClass(getClazz());
		criteria.add(Restrictions.like(propertyName, value.toString(), MatchMode.START));
		if (isDesc) {
			criteria.addOrder(Property.forName(orderBy).desc());
		} else {
			criteria.addOrder(Property.forName(orderBy).asc());
		}

		return (List<T>) this.query(criteria);
	}

	@Override
	public <T> List<T> query(String hql, Object[] parameters, Map<String, Object> parameterMap, String dataSourceName) {
		// TODO Auto-generated method stub
		return super.query(hql, parameters, parameterMap, dataSourceName);
	}

	@Override
	public List<T> getByOutUid(String outUid) throws Exception {
		return findByProperty("outUid", outUid);
	}
	
	public T getSingleByOutUid(String outUid) throws Exception {
		List<T> list = findByProperty("outUid", outUid);
		if(list != null){
			if(list.size() > 0){
				return list.get(0);
			} else {
				return null;
			}
		} else {
			return null;
		}
	}
}
